<!DOCTYPE html>
<html lang="zh-cn">
  <head>
    <meta charset="UTF-8">
    <title>Sucha's Blog - Archive for July, 2024</title>
    <meta name="generator" content="MarkdownProjectCompositor.lua">
    <meta name="author" content="Sucha">
    <meta name="keywords" content="suchang, programming, Linux, Lua">
    <meta name="description" content="Sucha's blog">
    <link rel="shortcut icon" href="../images/ico.png">
    <link rel="stylesheet" type="text/css" href="../styles/blog.css">
    <link rel="stylesheet" type="text/css" href="../styles/prism.min.css">
    <style id="site_theme"></style>
  </head>
  <body>
    <div id="body">
      <div id="text">
	   <!-- Page published by cmark-gfm begins here --><h1>Sucha's Blog ~ Archive for July, 2024</h1>
<p><a id="p2"></a></p>
<div class="date">25年7月28日 周日 13:53</div>
<h2>泥潭</h2>
<p>朋友给介绍的小说，这本小说的特点在于故事线，分三个部分，分别从同一事件的三个不同人物（角色）来围绕故事展开。</p>
<p>故事的背景是辛亥革命，主角 1 是其中的保皇派，主角 2 是其中的光复会成员（刚开始留日的时候是带着小辫子，之后逐渐转向了革命），主角 3 是神父，三个不同角色用不同的叙述、表现方式，展开了故事。</p>
<p>故事还可以，最特别的是三个角色，三种不同的叙述方式，以及三条时间线，值得一看吧。</p>
<p>不过，故事叙述比较宏大，像我，得花不少时间才能理清其中的故事线了。</p>
<div class="category"><a href="CategoryReading.html">CategoryReading</a> / <a href="2025-07.html#p2">Permalink</a> / <a href="https://github.com/lalawue/homepage/discussions/categories/blog" target="_blank">Discussion</a></div>
<p><a id="p1"></a></p>
<div class="date">25年7月19日 周六 20:32</div>
<h2>目录文件索引思考</h2>
<p>比如录像文件循环覆盖的逻辑，按照日分割建立文件夹，之后需要考虑如果存储空间不够，需要删除文件或目录，以及按照时间戳可以快速定位文件。</p>
<p>目前了解到的是都只有纯目录、文件的遍历操作，以及没有空间之后，删除日目录下，某个二级目录，作为存储空间的释放（获取）逻辑。</p>
<p>纯目录、文件的遍历操作，因为是嵌入式，nand 访问 IO 口速率比较低，以及 cpu 较差，所以时间上很慢，接口上为了适应这个限制，限制为 255 个文件后一次返回，之后客户端再次请求，传递进去的参数，是上一次返回的最后一个节点的结束时间。</p>
<p>如果类似 windows thumbs 或者 mac os DS_Store 的缓存文件索引策略，我觉得可以改善这个问题。</p>
<p>创建资源文件前，先创建（更新）索引文件，标记为待完成，资源文件完成后 ，再标记为已完成（open 接口，bit 反转），删除文件目录释放存储空间的时候，也同样更新相关标记就行。</p>
<p>若索引文件损坏或者不可用，逻辑上可以回退到纯目录、文件的遍历操作。</p>
<p>特别是文件查找，如果定义索引文件在日目录一级，日目录里面的文件可以根据二分查找，是相当快的，应该比目录遍历快得多，毕竟只需要读取一个索引文件。</p>
<p>索引文件的更新可能导致损坏，因此我才建议用 open 接口，bit 翻转，用先、后标记来保证，如果没有后标记，更精细的做法是校验相关资源文件，若文件是完整的，则可以更新后标记。</p>
<p>同样的，删除也可以用先、后标记来做，这个都没什么问题。</p>
<p>我觉得这样的操作是安全的，以及通过索引文件来定位、遍历资源文件内容是高效的。</p>
<div class="category"><a href="CategoryProgramming.html">CategoryProgramming</a> / <a href="2025-07.html#p1">Permalink</a> / <a href="https://github.com/lalawue/homepage/discussions/categories/blog" target="_blank">Discussion</a></div>
<p><a id="p0"></a></p>
<div class="date">25年7月13日 周日 23:11</div>
<h2>嵌入式系统文件更新的一些思考</h2>
<p>目前公司产品（一款嵌入式产品）的固件更新，是使用刷固件（实际上是写固定大小的 jffs2 分区）来做的，大概了解到其更新逻辑是，校验下载后的固件压缩包，校验解压后的固件文件系统包，重启更新（其实还需要教研一次固件文件系统包），刷固件到固定大小的 nand  flash 分区（这个时候还需要校验一次），之后再次重启，挂载相关的 jffs2 分区。</p>
<p>实话说，相对于后端 go 这样 static linked 的程序更新（shipping），固件程序的更新实在是太麻烦了，一方面 nand 存储不可靠（虽然 SD 卡等 nand 存储，主控本身保证了数据安全），另外一方面，文件系统挂载为只读处理也是问题，以及刷机，多次重启，很耗费时间，从最开始的 5 分钟慢慢成了现在的 10 分钟。</p>
<p>所以，我想能否改成这样的逻辑：</p>
<p>比如类似 nginx -r 重启加载某个进程（假设都是 linux 的系统），一个 master 进程，下面多个 app 进程（看业务需求），更新逻辑是：</p>
<ul>
<li>kill 掉业务 app 进程（可能是多个），拉起更新（刷新）进程</li>
<li>卸载 app 业务分区（假设仍是 jffs2）</li>
<li>校验固件压缩包，校验固件解压包，写入 jffs2 分区，校验 app 业务分区</li>
<li>重新挂载 jffs2 分区</li>
<li>kill 掉刷新进程，拉起业务进程 loading 进程</li>
<li>loading 进程每次启动（包括冷启动，热启动），都会校验 app 业务分区，然后再拉起 app 多个业务</li>
</ul>
<p>这样，用多进程的方式来进行热更新，其效率会比目前冷启动的效率高得多，当然这里面有不少细节需要确认</p>
<ul>
<li>app 业务分区，在多个业务进程被 kill 掉后，是能够被卸载的</li>
<li>app 业务分区被卸载后，能够被正常写入（或者挂载为 RW 分区，直接更新二进制包，启动只校验二进制包，其实也就是 .so）</li>
<li>app 业务分区有最新的 .so，worker 加载失败后，master 进程能够拉起非更新分区的旧版的 app 业务进程，并通知到 HOST 支持再次更新</li>
</ul>
<p>这样 HOST 仍能随时更新固件里面的业务进程，这要比单纯仅只读 jffs2 挂载的业务分区，更新的效率高得多。</p>
<p>当然，上述的想法，是基于一些我对固件更新的业务逻辑的了解上，做出的一些改进。</p>
<p>距离我上次在福建做类似的固件开发（linux 嵌入式业务开发），已经超过了 13 年，之前的两个不同产品的更新，一个是完全依赖网络（网卡的 IPXE），一个是 EEPROM，然后再带 nand flash（忘记多大了），跟现在的应该是有差别。</p>
<p>大概思路是这样，如果有可能的话，我觉得改进的效率是很高的，应该要比现在 10 分钟起步的更新快得多得多，但是要求是 linux 的多进程管理，以及同步的能力吧。</p>
<div class="category"><a href="CategoryProgramming.html">CategoryProgramming</a> / <a href="2025-07.html#p0">Permalink</a> / <a href="https://github.com/lalawue/homepage/discussions/categories/blog" target="_blank">Discussion</a></div>
<!-- Page published by cmark-gfm ends here -->
  <div id="foot">2004-<script>var d = new
	Date();document.write(d.getFullYear())</script> &copy;
	Sucha. Powered by MarkdownProjectCompositor.
  </div>
  </div><!-- text -->
  <div id="sidebar">
  </div><!-- sidebar -->
  <script src="../js/prism.min.js" async="async"></script>
  <script src="../js/blog_sidebar.js"></script>
  </div> <!-- body -->
</body>
</html>